﻿using Newtonsoft.Json;
using Org.BouncyCastle.Utilities;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Zocono.Infrastructure.Common;
using Zocono.WCS.Comm;
using Zocono.WCS.Domain.DomainRepository;
using Zocono.WCS.Domain.EntityInfo;
using Zocono.WCS.Domain.FSJDomain;
using Zocono.WCS.Domain.LogDomain;
using Zocono.WCS.Domain.PlcBytesObject;
using Zocono.WCS.Domain.PlcConnectPoolDomain;
using Zocono.WCS.Domain.ProcessModuleDomain;
using Zocono.WCS.Infrastructure.ApllicationDto.DtoWcsManage;
using Zocono.WCS.Infrastructure.ApllicationDto.WCSTaskDto;
using Zocono.WCS.WMSApiDomain.WebApi;

namespace Zocono.WCS.Domain.EquipmentProcessDomain.PlanarGeneralMessage
{
    /// <summary>
    /// 分选机挑选位置 挑选完剩余电芯上报 挑选位握手 2-0
    /// </summary>
    public class FenXuanNgUploadService : IPlanarGeneralPlcActionProcessService
    {
        private readonly IRedisHelper _IRedisHelper;
        private readonly ILogUtil _LogUtil;
        private readonly IPlcConnectionPool _PlcConnectionPool;
        private readonly IWorkTaskInfoRepository _WorkTaskInfoRepository;
        private readonly IPlcWriteDbInfoRepository _PlcWriteDbInfoRepository;
        private readonly IPlcConnectionInfoRepository _PlcConnectionInfoRepository;
        private readonly IPlcPointInfoRepositpry _IPlcPointInfoRepositpry;
        private readonly IPlcConnectionStateInfoRepository _IPlcConnectionStateInfoRepository;
        private readonly IRunLogInfoService _IRunLogInfoService;
        private readonly IPlcReadDbInfoRepository _PlcReadDbInfoRepository;
        private readonly IInterfaceLogInfoService _InterfaceLogInfoService;
        private readonly IFSJMesService _IFSJMesService;

        public FenXuanNgUploadService(IRedisHelper iRedisHelper, ILogUtil logUtil
            , IPlcConnectionPool plcConnectionPool
            , IWorkTaskInfoRepository workTaskInfoRepository
            , IPlcWriteDbInfoRepository plcWriteDbInfoRepository
            , IPlcConnectionInfoRepository plcConnectionInfoRepository,
            IPlcPointInfoRepositpry plcPointInfoRepositpry
             , IPlcConnectionStateInfoRepository plcConnectionStateInfoRepository
            , IRunLogInfoService runLogInfoService,
             IPlcReadDbInfoRepository plcReadDbInfoRepository,
             IInterfaceLogInfoService iterfaceLogInfoService,
            IFSJMesService iFSJMesService//,
                                         // AisleRequestService aisleRequestService
            )
        {
            _IRedisHelper = iRedisHelper;
            _LogUtil = logUtil;
            _PlcConnectionPool = plcConnectionPool;
            _WorkTaskInfoRepository = workTaskInfoRepository;
            _PlcWriteDbInfoRepository = plcWriteDbInfoRepository;
            _PlcConnectionInfoRepository = plcConnectionInfoRepository;
            _IPlcPointInfoRepositpry = plcPointInfoRepositpry;
            _IPlcConnectionStateInfoRepository = plcConnectionStateInfoRepository;
            _IRunLogInfoService = runLogInfoService;
            _PlcReadDbInfoRepository = plcReadDbInfoRepository;
            _InterfaceLogInfoService = iterfaceLogInfoService;
            _IFSJMesService = iFSJMesService;
        }

        public async Task ProcessActionMessageAsync(BytesObjectBase plcActionMessage, BytesObjectBase wcsActionMessage, EquipmentDbObject planarEquipmentDbObject/*, BytesObjectBase plcStateMassge*/)
        {
           /*
            * 处理逻辑
            * 1. 验证plc是否在线
            * 2. 验证当前设备是否报警
            * 3. 验证wcs任务，验证wcs当前子任务(待执行、执行中)，当前子任务已经是SC完成后更新了
            * 4. 组织plc报文，写入plc
            */

            var plcMessage = plcActionMessage as PlanarGeneralPlcActionBO;//Plc的动作报文
            var wcsMessage = wcsActionMessage as PlanarGeneralWcsActionBO;//Wcs的动作报文
            plcMessage.PalletBarcode = plcMessage.PalletBarcode.Trim();


            var ContainerBarcode = plcMessage.PalletBarcode.Trim();
            var EquipmentCode = plcMessage.EquipmentCode.Trim();
            
            var eqValue = _IRedisHelper.GetStringKey<string>($"PLC-WCS{EquipmentCode}");

            if (eqValue == null || string.IsNullOrEmpty(eqValue))
            {
                
                //_LogUtil.Debug($"{DateTime.Now}：挑选位【{plcMessage.EquipmentCode}】上报组盘信息业务开始！");
                //_IRedisHelper.SetStringKey($"PLC-WCS{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(2));
                //交互位写入
                var objectType = typeof(PlanarGeneralWriteWcsAction).Name;
                var writeConfig = await _PlcWriteDbInfoRepository.GetFirstAsync(it => it.EquipmentCode == plcMessage.EquipmentCode && it.ObjectType == objectType);

                PlanarGeneralWriteWcsAction writeBo = new PlanarGeneralWriteWcsAction(
                    writeConfig.PlcConnectionId,
                    writeConfig.ID,
                    writeConfig.DbCode,
                    writeConfig.DbStart,
                    objectType,
                    plcMessage.EquipmentCode.ToInt32(),
                    0,
                    0,
                    0,
                    ContainerBarcode,
                    0,
                    0);

                RunLogInfo runLogInfo = new RunLogInfo();
                runLogInfo.ContainerBarcode = plcMessage.PalletBarcode;
                runLogInfo.EquipmentCode = plcMessage.EquipmentCode;
                runLogInfo.RunType = "分选台挑选位";

                runLogInfo.RunLog = "分选台挑选位任务开始";

                var plcConn = _PlcConnectionPool.S7GetWritePlcConnection(plcMessage.PlcConnectionID);
                if (plcConn == null)
                {
                    //runLogInfo.RunLog = $"获取连接({plcMessage.PlcConnectionID})失败";
                    //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                    _LogUtil.Error($"分选台挑选位：托盘【{plcMessage.PalletBarcode}】分选台挑选位，PLC设备【{plcMessage.EquipmentCode}】,连接池无连接({plcMessage.PlcConnectionID})");
                    return;
                }
                var plcIPStates = await _IPlcConnectionStateInfoRepository.GetFirstAsync(l => l.PlcConnectionID == plcMessage.PlcConnectionID && l.Connected == true);
                if (plcIPStates == null)
                {
                    //runLogInfo.RunLog = $"{plcConn.IP}plc已离线";
                    //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                    _LogUtil.Error($"分选台挑选位：托盘【{plcMessage.PalletBarcode}】分选台挑选位，PLC设备【{plcMessage.EquipmentCode}】,获取连接({plcMessage.PlcConnectionID})失败");
                    return;
                }
                //if (plcMessage.AlrmCode != 0)
                //{
                //    runLogInfo.RunLog = $"报警,报警代码：{plcMessage.AlrmCode}";
                //    await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                //    return;
                //}

                //校验plc信息是否有托盘码
                if (string.IsNullOrEmpty(plcMessage.PalletBarcode) || plcMessage.PalletBarcode.Length != 10)
                {
                    writeBo.AlrmCode = 102;
                    writeBo.ActionType = 99;
                    var flag = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                    _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                    return;
                }
                //获取组盘位电芯信息
                var objectTypeCell = typeof(PlanarGeneralPlcActionBOFx).Name;
                var barcodeDb = await _PlcReadDbInfoRepository
                        .GetFirstAsync(it =>
                        it.DbCode == 1000 &&
                        it.EquipmentCode == "FX-" + plcMessage.EquipmentCode
                    );

                if (barcodeDb == null)
                {
                    _LogUtil.Error($"分选台挑选位：托盘【{plcMessage.PalletBarcode}】分选台挑选位，PLC设备【FX-{plcMessage.EquipmentCode}】,获取组盘机电芯信息读DB失败！请配置分选组盘机电芯读DB");
                    return;
                }
                ////读取条码
                //var plcConn = _PlcConnectionPool.S7GetWritePlcConnection(plcMessage.PlcConnectionID);
                try
                {
                    
                    //_LogUtil.Debug($"{DateTime.Now}：挑选位【{plcMessage.EquipmentCode}】开始读取电芯信息！");
                    byte[] barcodeBytes = await plcConn.ReadDbAsync(barcodeDb.DbCode, barcodeDb.DbStart, barcodeDb.DbLength);
                    if (barcodeBytes != null)
                    {
                        //读取成功
                        PlanarGeneralPlcActionBOFx readPlcBarcode = new PlanarGeneralPlcActionBOFx();
                        readPlcBarcode.Serialize(
                            barcodeDb.PlcConnectionID,
                            barcodeDb.ID,
                            barcodeDb.DbStart,
                            barcodeBytes.Count(),
                            0,
                            barcodeDb.DbLength,
                            barcodeDb.ProcessModuleName,
                            barcodeDb.EquipmentCode,
                            barcodeBytes
                            );
                        //_LogUtil.Debug($"{DateTime.Now}：分选台挑选位:读取电芯数据：【FX-{EquipmentCode}】-->" + JsonHelper.SerializeObject(readPlcBarcode));
                        
                        WcsOkResultUploadInfo upInfo = new WcsOkResultUploadInfo();
                        upInfo.ContainerCode = plcMessage.PalletBarcode;
                        upInfo.EquipmentCode = plcMessage.EquipmentCode;
                        upInfo.TiaoXuanEquipmentCode = plcMessage.EquipmentCode;
                        upInfo.TiaoXuanContainerCode = plcMessage.PalletBarcode;
                        List<ContainerCellsMsgDto> cells = new List<ContainerCellsMsgDto>();

                        //List<BatteryUpDataDto> putInDatas = new List<BatteryUpDataDto>();
                        //封装上报数据
                        foreach (var item in readPlcBarcode.Infos)
                        {
                            if (!string.IsNullOrEmpty(item.code))
                            {
                                //BatteryUpDataDto putInData = new BatteryUpDataDto();
                                //putInData.EquipCode = EquipmentCode;
                                //putInData.CellCode = item.code;
                                //putInData.TrayCode = ContainerBarcode;
                                //putInData.Position = item.location.ToString();
                                //putInDatas.Add(putInData);
                                ContainerCellsMsgDto cell = new ContainerCellsMsgDto();
                                cell.CellPosttion = item.location.ToString();
                                cell.CellCode = item.code;
                                cells.Add(cell);
                            }
                        }
                        upInfo.CellDataDtos = cells;
                        //上报挑选完结果 单电芯解绑
                        //_LogUtil.Debug($"{DateTime.Now}：挑选位【{plcMessage.EquipmentCode}】开始请求上报电芯信息！");
                        var upDataResult = await WCSMessageWithWMSApi.WCSUploadNgResultAsync(upInfo);
                        _LogUtil.Debug($"分选台挑选位:上报挑选完毕：【FX-{EquipmentCode}】请求参数-->{JsonHelper.SerializeObject(upInfo)}--->返回结果：{JsonHelper.SerializeObject(upDataResult)}");

                        if (upDataResult.Result)
                        {
                            //writeBo.ActionType = plcMessage.ActionType;
                            //var res = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                            //if (res)
                            //{
                            //    // 记录运行日志
                            //    runLogInfo.RunLog = $"分选台挑选位：托盘【{plcMessage.PalletBarcode}】分选台挑选位，PLC设备【{plcMessage.EquipmentCode}】分选挑选位挑选完上报成功，写入报文成功！报文内容：{JsonConvert.SerializeObject(writeBo)}";
                            //    await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);


                                //上报分选结果组盘
                                //上报分选结果组盘
                                //上报分选结果组盘
                                //获取组盘位电芯信息
                                //var objectTypeCell = typeof(PlanarGeneralPlcActionBOFx).Name;
                                
                            //_LogUtil.Debug($"{DateTime.Now}：挑选位【{plcMessage.EquipmentCode}】上报电芯信息返回！");
                            try
                            {
                                if (barcodeBytes != null)
                                {
                                    List<BatteryUpDataDto> putInDatas = new List<BatteryUpDataDto>();
                                    //封装上报数据
                                    foreach (var item in readPlcBarcode.Infos)
                                    {
                                        if (!string.IsNullOrEmpty(item.code))
                                        {
                                            BatteryUpDataDto putInData = new BatteryUpDataDto();
                                            putInData.EquipCode = EquipmentCode;
                                            putInData.CellCode = item.code;
                                            putInData.TrayCode = ContainerBarcode;
                                            putInData.Position = item.location.ToString();
                                            putInDatas.Add(putInData);
                                        }
                                    }
                                    
                                    //_LogUtil.Debug($"{DateTime.Now}：挑选位【{plcMessage.EquipmentCode}】开始上报组盘电芯信息！");
                                    //请求分选机上传MES 分档结果
                                    var upDataResultMes = await WCSMessageWithWMSApi.PostMesResultAsync(putInDatas, _InterfaceLogInfoService);
                                    _LogUtil.Debug($"{DateTime.Now}：分选台挑选位:上报组盘：【FX-{EquipmentCode}】请求参数-->{JsonHelper.SerializeObject(putInDatas)}--->返回结果：{JsonHelper.SerializeObject(upDataResult)}");

                                    if (upDataResultMes.success)
                                    {
                                        writeBo.PalletType = plcMessage.PalletType;
                                        writeBo.ActionType = plcMessage.ActionType;
                                        
                                        //_LogUtil.Debug($"{DateTime.Now}：挑选位【{plcMessage.EquipmentCode}】开始写入握手！");
                                        var resT = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                                        if (resT)
                                        {
                                            //_LogUtil.Debug($"{DateTime.Now}：挑选位【{plcMessage.EquipmentCode}】写入握手成功！");
                                            // 记录运行日志
                                            runLogInfo.RunLog = $"分选台挑选位：托盘【{plcMessage.PalletBarcode}】分选台组盘，PLC设备【{plcMessage.EquipmentCode}】分选台组盘任上报成功，写入报文成功！报文内容：{JsonConvert.SerializeObject(writeBo)}";
                                            await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                                        }
                                    }
                                    else
                                    {
                                        writeBo.AlrmCode = 129;
                                        writeBo.ActionType = 99;
                                        await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                                        _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                                        _LogUtil.Error($"分选台挑选位：托盘【{plcMessage.PalletBarcode}】分选台组盘，PLC设备【FX-{plcMessage.EquipmentCode}】,上报分选机组盘结果失败");
                                    }
                                }
                                else
                                {
                                    writeBo.AlrmCode = 130;
                                    writeBo.ActionType = 99;
                                    await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                                    _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                                    _LogUtil.Error($"分选台组盘：托盘【{plcMessage.PalletBarcode}】分选台组盘，PLC设备【FX-{plcMessage.EquipmentCode}】,读取分选机电芯数据失败！");
                                    return;
                                }
                            }
                            catch (Exception ex)
                            {
                                writeBo.AlrmCode = 131;
                                writeBo.ActionType = 99;
                                await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                                _LogUtil.Error($"分选台组盘：托盘【{plcMessage.PalletBarcode}】分选台组盘，PLC设备【FX-{plcMessage.EquipmentCode}】,上报电芯结果报错EX={ex.Message}");
                                return;
                            }
                            //解除锁定
                            //_IRedisHelper.SetStringKey($"PLC-WCS{plcMessage.EquipmentCode}", "", TimeSpan.FromSeconds(10));
                            //}
                        }
                        //else
                        //{
                        //    writeBo.AlrmCode = 129;
                        //    writeBo.ActionType = 99;
                        //    var res = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                        //    _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                        //    _LogUtil.Error($"分选台挑选位：托盘【{plcMessage.PalletBarcode}】分选台挑选位，PLC设备【FX-{plcMessage.EquipmentCode}】,分选挑选位挑选完上报结果失败");
                        //}
                    }
                    else
                    {
                        writeBo.AlrmCode = 130;
                        writeBo.ActionType = 99;
                        var res = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                        _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                        _LogUtil.Error($"分选台挑选位：托盘【{plcMessage.PalletBarcode}】分选台挑选位，PLC设备【FX-{plcMessage.EquipmentCode}】,读取分选机电芯数据失败！");
                        return;
                    }
                }
                catch (Exception ex)
                {
                    writeBo.AlrmCode = 131;
                    writeBo.ActionType = 99;
                    var res = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                    _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                    _LogUtil.Error($"分选台挑选位：托盘【{plcMessage.PalletBarcode}】分选台挑选位，PLC设备【FX-{plcMessage.EquipmentCode}】,分选挑选位挑选完上报电芯结果报错EX={ex.Message}");
                    return;
                }
            }
            

        }
    }
}
